
#pragma once
#include <boost/asio.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/array.hpp>
#include <atomic>
#include <chrono>
#include <vector>
#include <string_view>
#include "cc/llhttp.h"
#include "cc/parser.h"
#include "cc/http_response.h"
#include "cc/logging.h"
#include "cc/detail.h"
#include "cc/middleware_context.h"
#include "cc/socket_adaptors.h"
#include "cc/compression.h"
namespace cc { static std::string_view expect_100_continue("HTTP/1.1 100 Continue\r\n\r\n", 25); namespace detail { template <typename MW>struct check_before_handle_arity_3_const { template <typename T, void(T::*)(Req&, Res&, typename MW::Ctx&)const = &T::before_handle > struct get {}; }; template <typename MW>struct check_before_handle_arity_3 { template <typename T, void(T::*)(Req&, Res&, typename MW::Ctx&) = &T::before_handle > struct get {}; }; template <typename MW>struct check_after_handle_arity_3_const { template <typename T, void(T::*)(Req&, Res&, typename MW::Ctx&)const = &T::after_handle > struct get {}; }; template <typename MW>struct check_after_handle_arity_3 { template <typename T, void(T::*)(Req&, Res&, typename MW::Ctx&) = &T::after_handle > struct get {}; }; template <typename T>struct is_before_handle_arity_3_impl { template <typename C> static std::true_type f(typename check_before_handle_arity_3_const<T>::template get<C>*); template <typename C> static std::true_type f(typename check_before_handle_arity_3<T>::template get<C>*); template <typename C> static std::false_type f(...); public: static const bool value = decltype(f<T>(nullptr))::value; }; template <typename T> struct is_after_handle_arity_3_impl { template <typename C> static std::true_type f(typename check_after_handle_arity_3_const<T>::template get<C>*); template <typename C> static std::true_type f(typename check_after_handle_arity_3<T>::template get<C>*); template <typename C> static std::false_type f(...); public: static const bool value = decltype(f<T>(nullptr))::value; }; template <typename MW, typename Context, typename ParentContext> typename std::enable_if<!is_before_handle_arity_3_impl<MW>::value>::type before_handler_call(MW& mw, Req& req, Res& res, Context& ctx, ParentContext& ) { mw.before_handle(req, res, ctx.template get<MW>(), ctx); } template <typename MW, typename Context, typename ParentContext> typename std::enable_if<is_before_handle_arity_3_impl<MW>::value>::type before_handler_call(MW& mw, Req& req, Res& res, Context& ctx, ParentContext& ) { mw.before_handle(req, res, ctx.template get<MW>()); } template <typename MW, typename Context, typename ParentContext> typename std::enable_if<!is_after_handle_arity_3_impl<MW>::value>::type after_handler_call(MW& mw, Req& req, Res& res, Context& ctx, ParentContext& ) { mw.after_handle(req, res, ctx.template get<MW>(), ctx); } template <typename MW, typename Context, typename ParentContext> typename std::enable_if<is_after_handle_arity_3_impl<MW>::value>::type after_handler_call(MW& mw, Req& req, Res& res, Context& ctx, ParentContext& ) { mw.after_handle(req, res, ctx.template get<MW>()); } template <int N, typename Context, typename Container, typename CurrentMW, typename ... Middlewares> bool middleware_call_helper(Container& middlewares, Req& req, Res& res, Context& ctx) { using parent_context_t = typename Context::template partial<N - 1>; before_handler_call<CurrentMW, Context, parent_context_t>(std::get<N>(middlewares), req, res, ctx, static_cast<parent_context_t&>(ctx)); if (res.is_completed()) { after_handler_call<CurrentMW, Context, parent_context_t>(std::get<N>(middlewares), req, res, ctx, static_cast<parent_context_t&>(ctx)); return true; } if (middleware_call_helper<N + 1, Context, Container, Middlewares...>(middlewares, req, res, ctx)) { after_handler_call<CurrentMW, Context, parent_context_t>(std::get<N>(middlewares), req, res, ctx, static_cast<parent_context_t&>(ctx)); return true; } return false; } template <int N, typename Context, typename Container> bool middleware_call_helper(Container& , Req& , Res& , Context& ) { return false; } template <int N, typename Context, typename Container> typename std::enable_if<(N < 0)>::type after_handlers_call_helper(Container& , Context& , Req& , Res& ) {} template <int N, typename Context, typename Container> typename std::enable_if<(N == 0)>::type after_handlers_call_helper(Container& middlewares, Context& ctx, Req& req, Res& res) { using parent_context_t = typename Context::template partial<N - 1>; using CurrentMW = typename std::tuple_element<N, typename std::remove_reference<Container>::type>::type; after_handler_call<CurrentMW, Context, parent_context_t>(std::get<N>(middlewares), req, res, ctx, static_cast<parent_context_t&>(ctx)); } template <int N, typename Context, typename Container> typename std::enable_if<(N > 0)>::type after_handlers_call_helper(Container& middlewares, Context& ctx, Req& req, Res& res) { using parent_context_t = typename Context::template partial<N - 1>; using CurrentMW = typename std::tuple_element<N, typename std::remove_reference<Container>::type>::type; after_handler_call<CurrentMW, Context, parent_context_t>(std::get<N>(middlewares), req, res, ctx, static_cast<parent_context_t&>(ctx)); after_handlers_call_helper<N - 1, Context, Container>(middlewares, ctx, req, res); } } using namespace boost; using tcp = asio::ip::tcp;  template <typename Adaptor, typename Handler, typename ... Middlewares> class Connection : http_parser { friend struct cc::Res; public: Connection(boost::asio::io_service& io_service, Handler* handler, std::tuple<Middlewares...>* middlewares, std::function<std::string()>& get_cached_date_str_f, detail::dumb_timer_queue& timer_queue, typename Adaptor::Ctx* adaptor_ctx_, std::atomic<uint16_t>& queue_length) : adaptor_(io_service, adaptor_ctx_), handler_(handler), parser_(this), middlewares_(middlewares), get_cached_date_str(get_cached_date_str_f), timer_queue_(timer_queue), queue_length_(queue_length) {} ~Connection() { timer_cancel(); --queue_length_; res.complete_request_handler_ = nullptr; } decltype(std::declval<Adaptor>().raw_socket())& socket() { return adaptor_.raw_socket(); } inline void start() { adaptor_.start([this](const boost::system::error_code& ec) { if (!ec) {  do_read(); } else { adaptor_.close(); delete this; } }); } inline void handle_header() {  if (parser_.http_major == 1 && parser_.http_minor == 1 && get_header_value(parser_.headers, RES_Ex) == "100-continue") { buffers_.clear(); buffers_ += expect_100_continue; do_write(); } }  void handle() {  buffers_.clear(); bool is_invalid_request = false; req_ = std::move(parser_.to_request()); req_.remote_ip_address = adaptor_.remote_endpoint().address().to_string(); add_keep_alive_ = parser_.keep_alive; close_connection_ = parser_.close_connection; if (parser_.http_major == 1 && parser_.http_minor == 1) {     LOG_INFO(req_.get_header_value(RES_upgrade) << " [upgrade: " << (int)parser_.flags << " ] [finish: " << (int)parser_.finish << " ] [method: " << (int)req_.method << " ]"); if (parser_.upgrade) {
#ifdef ENABLE_SSL
  if (handler_->use_ssl_) { if (req_.get_header_value(RES_upgrade) == "h2") {} } else if (req_.get_header_value(RES_upgrade) == "h2c") {} else 
#endif
 { LOG_WARNING("close_connection_:h2c"); close_connection_ = true; handler_->handle_upgrade(req_, res, std::move(adaptor_)); return; } } } LOG_INFO("Request: " << boost::lexical_cast<std::string>(adaptor_.remote_endpoint()) << " " << this << " HTTP/" << parser_.http_major << "." << parser_.http_minor << ' ' << m2s(req_.method) << " " << req_.url); need_to_call_after_handlers_ = false; if (req_.method == HTTP::OPTIONS) { res.code = 204; res.end(); complete_request(); } else if (!is_invalid_request) { res.complete_request_handler_ = [] {}; ctx_ = detail::Ctx<Middlewares...>(); req_.middleware_context = static_cast<void*>(&ctx_); req_.io_service = &adaptor_.get_io_service();   if (!res.completed_) { LOG_WARNING("!res.completed_" << add_keep_alive_); res.complete_request_handler_ = [this] { this->complete_request(); }; need_to_call_after_handlers_ = true; handler_->handle(req_, res); if (add_keep_alive_) res.set_header(Res_con, "Keep-Alive"); } else { LOG_WARNING("!complete_request"); complete_request(); } } else { LOG_WARNING("&complete_request"); complete_request(); } }  inline void complete_request() { LOG_INFO("Response: " << this << ' ' << req_.raw_url << ' ' << res.code << ' ' << close_connection_); if (need_to_call_after_handlers_) { need_to_call_after_handlers_ = false;  detail::after_handlers_call_helper< (static_cast<int>(sizeof...(Middlewares)) - 1), decltype(ctx_), decltype(*middlewares_)> (*middlewares_, ctx_, req_, res); } set_status(res.code);    
#ifdef ENABLE_SSL
 std::string location = res.get_header_value(RES_Loc); if (location.empty()) { location.insert(0, "https://" + req_.get_header_value(Res_host)); res.add_header(Res_loc, location); }
#endif
 if (res.is_file > 0) { buffers_.reserve(0x4f); prepare_buffers(); buffers_ += Res_Ca; buffers_ += Res_seperator; buffers_ += FILE_TIME; buffers_ += Res_crlf; buffers_ += RES_Xc; buffers_ += Res_seperator; buffers_ += RES_No; buffers_ += Res_crlf; if (res.is_file == 1) { res.is_file = 0; buffers_ += Res_crlf; do_write_static(); } else { res.is_file = 0; buffers_ += RES_CT; buffers_ += Res_seperator; buffers_ += RES_Txt; buffers_ += Res_crlf; uint64_t times = hackUrl(res.path_.substr(detail::directory_.size()).data()); if (RES_CACHE_TIME[times] > nowStamp()) {
#ifdef ENABLE_COMPRESSION
 switch (handler_->compression_algorithm()) { case compression::GZIP: buffers_ += RES_CE; buffers_ += Res_seperator; buffers_ += RES_gzip; buffers_ += Res_crlf; break; default: buffers_ += RES_CE; buffers_ += Res_seperator; buffers_ += RES_deflate; buffers_ += Res_crlf; }
#endif
 res.body = RES_CACHE_MENU[times]; goto __; } std::ifstream inf(res.path_, std::ios::in | std::ios::binary); RES_CACHE_TIME[times] = nowStamp(CACHE_MENU_TIME_SECOND); std::string s = { std::istreambuf_iterator<char>(inf), std::istreambuf_iterator<char>() }; res.body = std::move(s); inf.close();
#ifdef ENABLE_COMPRESSION
   switch (handler_->compression_algorithm()) { case compression::GZIP: res.body = std::move(compression::compress_string(res.body, compression::algorithm::GZIP)); buffers_ += RES_CE; buffers_ += Res_seperator; buffers_ += RES_gzip; buffers_ += Res_crlf; break; default: res.body = std::move(compression::compress_string(res.body, compression::algorithm::DEFLATE)); buffers_ += RES_CE; buffers_ += Res_seperator; buffers_ += RES_deflate; buffers_ += Res_crlf; }
#endif
 RES_CACHE_MENU[times] = res.body; goto __; } } else { buffers_.reserve(0x3f); prepare_buffers();
#ifdef ENABLE_COMPRESSION
 if (res.compressed && res.body.size() > 0xff) { LOG_WARNING("&ENABLE_COMPRESSION"); switch (handler_->compression_algorithm()) { case compression::GZIP: res.body = std::move(compression::compress_string(res.body, compression::algorithm::GZIP)); buffers_ += RES_CE; buffers_ += Res_seperator; buffers_ += RES_gzip; buffers_ += Res_crlf; break; default: res.body = std::move(compression::compress_string(res.body, compression::algorithm::DEFLATE)); buffers_ += RES_CE; buffers_ += Res_seperator; buffers_ += RES_deflate; buffers_ += Res_crlf; } }
#endif
 if (!res.headers.count(RES_CT)) { buffers_ += RES_CT; buffers_ += Res_seperator; buffers_ += RES_Txt; buffers_ += Res_crlf; } detail::middleware_call_helper<0, decltype(ctx_), decltype(*middlewares_), Middlewares...>(*middlewares_, req_, res, ctx_); __: buffers_ += Res_content_length_tag; buffers_ += std::to_string(res.body.size()); buffers_ += Res_crlf;
#if SHOW_SERVER_NAME
 buffers_ += Res_server_tag; buffers_ += SERVER_NAME; buffers_ += Res_crlf;
#endif
 buffers_ += Res_date_tag; buffers_ += get_cached_date_str(); buffers_ += Res_crlf; buffers_ += Res_crlf; do_write_general(); } } private: inline void set_status(uint16_t status) { res.code = status; switch (status) { case 200:status_ = "200 OK\r\n"; break; case 201:status_ = "201 Created\r\n"; break; case 202:status_ = "202 Accepted\r\n"; break; case 203:status_ = "203 Non-Authoritative Information\r\n"; break; case 204:status_ = "204 No Content\r\n"; break; case 301:status_ = "301 Moved Permanently\r\n"; break; case 302:status_ = "302 Found\r\n"; break; case 303:status_ = "303 See Other\r\n"; break; case 304:status_ = "304 Not Modified\r\n"; break; case 307:status_ = "307 Temporary redirect\r\n"; break; case 400:status_ = "400 Bad Request\r\n"; res.body = status_; break; case 401:status_ = "401 Unauthorized\r\n"; res.body = status_; break; case 402:status_ = "402 Payment Required\r\n"; res.body = status_; break; case 403:status_ = "403 Forbidden\r\n"; res.body = status_; break; case 405:status_ = "405 HTTP verb used to access this page is not allowed\r\n"; res.body = status_; break; case 406:status_ = "406 Browser does not accept the MIME type of the requested page\r\n"; res.body = status_; break; case 409:status_ = "409 Conflict\r\n"; res.body = status_; break; case 500:status_ = "500 Internal Server Error\r\n"; break; case 501:status_ = "501 Not Implemented\r\n"; res.body = status_; break; case 502:status_ = "502 Bad Gateway\r\n"; res.body = status_; break; case 503:status_ = "503 Service Unavailable\r\n"; res.body = status_; break; default:status_ = "404 Not Found\r\n"; res.body = status_; break; } } inline void prepare_buffers() { buffers_ += Res_http_status; buffers_ += status_;  for (auto& kv : res.headers) { buffers_ += kv.first; buffers_ += Res_seperator; buffers_ += kv.second; buffers_ += Res_crlf; }
#ifdef AccessControlAllowCredentials
 buffers_ += RES_AcC; buffers_ += AccessControlAllowCredentials; buffers_ += Res_crlf;
#endif
#ifdef AccessControlAllowHeaders
 buffers_ += RES_AcH; buffers_ += AccessControlAllowHeaders; buffers_ += Res_crlf;
#endif
#ifdef AccessControlAllowMethods
 buffers_ += RES_AcM; buffers_ += AccessControlAllowMethods; buffers_ += Res_crlf;
#endif
#ifdef AccessControlAllowOrigin
 buffers_ += RES_AcO; buffers_ += AccessControlAllowOrigin; buffers_ += Res_crlf;
#endif
 }  inline void do_write_static() { LOG_WARNING("do_write_static ."); boost::asio::write(adaptor_.socket(), boost::asio::buffer(buffers_)); char buf[2048]; std::ifstream is(res.path_.data(), std::ios::in | std::ios::binary); size_t l = 0; $:l = is.read(buf, 2048).gcount(); if (l) { buffers_.clear(); buffers_.assign(buf, buf + l); boost::asio::write(adaptor_.socket(), boost::asio::buffer(buffers_)); goto $; } buffers_.clear(); is_writing = false; if (close_connection_) { LOG_WARNING("close static ."); adaptor_.shutdown_write(); adaptor_.close(); check_destroy(); }  res.end(); res.clear(); }  inline void do_write_general() { if (res.body.length() < res_stream_threshold_) {   buffers_ += res.body; do_write(); if (need_to_start_read_after_complete_) { need_to_start_read_after_complete_ = false; timer_cancel(); start_deadline(); do_read(); } } else { LOG_WARNING("do_write_general ."); is_writing = true; boost::asio::write(adaptor_.socket(), boost::asio::buffer(buffers_)); buffers_.clear(); if (res.body.length() > 0) { size_t i = 0, k = 8192, l = res.body.length(); std::string_view buf(res.body.c_str(), l); while (l > k) { boost::asio::write(adaptor_.socket(), boost::asio::buffer(buf.substr(i, k))); i += k; k += i;  }   boost::asio::write(adaptor_.socket(), boost::asio::buffer(buf.substr(i, l))); res.body.clear(); }  is_writing = false; if (close_connection_) { LOG_WARNING("close general ."); adaptor_.shutdown_write(); adaptor_.close(); check_destroy(); }  res.end(); res.clear(); } } inline void do_read() { is_reading = true;     adaptor_.socket().async_read_some(boost::asio::buffer(buffer_), [this](const boost::system::error_code& ec, std::size_t bytes_transferred) { if (bytes_transferred && !ec && parser_.feed(buffer_.data(), bytes_transferred)) { if (!need_to_call_after_handlers_) { LOG_WARNING("read after_handlers ");  timer_cancel(); start_deadline(); do_read(); } else if (close_connection_) { LOG_WARNING("read end!"); timer_cancel(); is_reading = false; check_destroy();  } else {    need_to_start_read_after_complete_ = true; LOG_WARNING("read after!"); } } else { is_reading = false; adaptor_.shutdown_read(); adaptor_.close(); check_destroy(); } }); }  inline void do_write() { is_writing = true; boost::asio::async_write(adaptor_.socket(), boost::asio::buffer(buffers_), [this](const boost::system::error_code& ec, std::size_t ) { is_writing = false; res.clear(); if (!ec) { LOG_WARNING("do_write end!"); if (close_connection_) {  adaptor_.shutdown_write(); adaptor_.close(); check_destroy(); } } else { check_destroy();   } }); } inline void timer_cancel() { if (timer_cancel_key_)timer_queue_.cancel(timer_cancel_key_);
#if DEFAULT_ENABLE_LOGGING
 else { LOG_WARNING(" @key:< " << timer_cancel_key_ << " >"); }
#endif
 } inline void check_destroy() { if (!is_reading && !is_writing) { LOG_WARNING("destroy !"); delete this; } } inline void start_deadline(unsigned short&& i = std::forward<unsigned short>(cc::detail::dumb_timer_queue::tick)) { timer_cancel_key_ = timer_queue_.add([this] { if (!adaptor_.is_open()) { return; } adaptor_.shutdown_readwrite(); adaptor_.close(); }, i); LOG_WARNING(" +key:< " << timer_cancel_key_ << " >"); } private: Adaptor adaptor_; Handler* handler_; boost::array<char, 0x3ff> buffer_; const char* status_ = "404 Not Found\r\n";  constexpr static unsigned int res_stream_threshold_ = 63 * 1024; HTTPParser<Connection> parser_; detail::dumb_timer_queue& timer_queue_; uint16_t timer_cancel_key_ = 0; std::atomic<uint16_t>& queue_length_; Req req_; Res res; std::string buffers_; bool is_reading{}; bool is_writing{}; bool add_keep_alive_{}; bool close_connection_ = false; bool need_to_call_after_handlers_{}; bool need_to_start_read_after_complete_{}; std::tuple<Middlewares...>* middlewares_; detail::Ctx<Middlewares...> ctx_; std::function<std::string()>& get_cached_date_str; };}